home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / CompiledEffect / CompiledEffect.cs next >
Encoding:
Text File  |  2004-09-27  |  23.1 KB  |  495 lines

  1. //-----------------------------------------------------------------------------
  2. // File: CompiledEffect.cs
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8.  
  9.  
  10. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  11. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  12.  
  13. using System;
  14. using Microsoft.DirectX;
  15. using Microsoft.DirectX.Direct3D;
  16. using Microsoft.Samples.DirectX.UtilityToolkit;
  17.  
  18. namespace CompiledEffectSample
  19. {
  20.     /// <summary>CompiledEffect Sample Class</summary>
  21.     public class CompiledEffect : IFrameworkCallback, IDeviceCreation
  22.     {
  23.         #region Creation
  24.         /// <summary>Create a new instance of the class</summary>
  25.         public CompiledEffect(Framework f) 
  26.         { 
  27.             // Store framework
  28.             sampleFramework = f; 
  29.             // Create dialogs
  30.             hud = new Dialog(sampleFramework); 
  31.         }
  32.         #endregion
  33.  
  34.         // constants
  35.         private static readonly ColorValue WhiteColor = new ColorValue(1.0f,1.0f,1.0f,1.0f);
  36.  
  37.         // Variables
  38.         private Framework sampleFramework = null; // Framework for samples
  39.         private Font statsFont = null; // Font for drawing text
  40.         private Sprite textSprite = null; // Sprite for batching text calls
  41.         private Effect effect = null; // D3DX Effect Interface
  42.         private ModelViewerCamera camera = new ModelViewerCamera(); // A model viewing camera
  43.         private bool isHelpShowing = true; // If true, renders the UI help text
  44.         private Dialog hud = null; // dialog for standard controls
  45.         private FrameworkMesh mesh = null; // Mesh object
  46.         private Vector3 objectCenter; // Center of bounding sphere of object
  47.         private float objectRadius; // Radius of bounding sphere of object
  48.         private Matrix worldCenter; // World matrix to center the mesh
  49.  
  50.         // Effect handles
  51.         private EffectHandle timeHandle = null; 
  52.         private EffectHandle worldHandle = null; 
  53.         private EffectHandle meshTextureHandle = null; 
  54.         private EffectHandle worldViewHandle = null; 
  55.         private EffectHandle techniqueHandle = null; 
  56.  
  57.         // HUD Ui Control constants
  58.         private const int ToggleFullscreen = 1;
  59.         private const int ToggleReference = 3;
  60.         private const int ChangeDevice = 4;
  61.  
  62.         /// <summary>
  63.         /// Called during device initialization, this code checks the device for some 
  64.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  65.         /// </summary>
  66.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  67.         {
  68.             // No fallback, need at least PS1.1
  69.             if (caps.PixelShaderVersion < new Version(1,1))
  70.                 return false;
  71.  
  72.             // Skip back buffer formats that don't support alpha blending
  73.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  74.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  75.                 return false;
  76.  
  77.             return true;
  78.         }
  79.  
  80.         /// <summary>
  81.         /// This callback function is called immediately before a device is created to allow the 
  82.         /// application to modify the device settings. The supplied settings parameter 
  83.         /// contains the settings that the framework has selected for the new device, and the 
  84.         /// application can make any desired changes directly to this structure.  Note however that 
  85.         /// the sample framework will not correct invalid device settings so care must be taken 
  86.         /// to return valid device settings, otherwise creating the Device will fail.  
  87.         /// </summary>
  88.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  89.         {
  90.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  91.             // then switch to SWVP.
  92.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  93.                 (caps.VertexShaderVersion < new Version(1,1)) )
  94.             {
  95.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  96.             }
  97.             else
  98.             {
  99.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  100.             }
  101.  
  102.             // This application is designed to work on a pure device by not using 
  103.             // any get methods, so create a pure device if supported and using HWVP.
  104.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  105.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  106.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  107.  
  108.             // Debugging vertex shaders requires either REF or software vertex processing 
  109.             // and debugging pixel shaders requires REF.  
  110. #if(DEBUG_VS)
  111.             if (settings.DeviceType != DeviceType.Reference )
  112.             {
  113.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  114.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  115.             }
  116. #endif
  117. #if(DEBUG_PS)
  118.             settings.DeviceType = DeviceType.Reference;
  119. #endif
  120.  
  121.         }
  122.  
  123.         /// <summary>
  124.         /// This event will be fired immediately after the Direct3D device has been 
  125.         /// created, which will happen during application initialization and windowed/full screen 
  126.         /// toggles. This is the best location to create Pool.Managed resources since these 
  127.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  128.         /// here should be released in the Disposing event. 
  129.         /// </summary>
  130.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  131.         {
  132.             // Initialize the stats font
  133.             statsFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
  134.                 Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
  135.                 , "Arial");
  136.  
  137.             // Load the mesh
  138.             mesh = new FrameworkMesh(e.Device, "dwarf\\dwarf.x");
  139.  
  140.             // Find the mesh's center, then generate a centering matrix
  141.             using(VertexBuffer vb = mesh.SystemMesh.VertexBuffer)
  142.             {
  143.                 using (GraphicsStream stm = vb.Lock(0, 0, LockFlags.None))
  144.                 {
  145.                     try
  146.                     {
  147.                         objectRadius = Geometry.ComputeBoundingSphere(stm,
  148.                             mesh.SystemMesh.NumberVertices, mesh.SystemMesh.VertexFormat, out objectCenter);
  149.  
  150.                         worldCenter = Matrix.Translation(-objectCenter);
  151.                     }
  152.                     finally
  153.                     {
  154.                         vb.Unlock();
  155.                     }
  156.                 }
  157.             }
  158.  
  159.             // Try to find the D3DX Effect file
  160.             try
  161.             {
  162.                 string path = Utility.FindMediaFile("CompiledEffect.fxo");
  163.  
  164.                 // Since we are loading a binary file here and this effect has already been compiled,
  165.                 // you can not pass compiler flags here (for example to debug the shaders). 
  166.                 // To debug the shaders, you must pass these flags to the compiler that generated the
  167.                 // binary (for example fxc.exe).  In this sample, there is an extra Visual Studio configuration
  168.                 // called "Debug Shaders" that pass the debug shader flags to fxc.exe.
  169.                 effect = ResourceCache.GetGlobalInstance().CreateEffectFromFile(e.Device,
  170.                     path, null, null, ShaderFlags.None, null);
  171.             }
  172.             catch(MediaNotFoundException)
  173.             {
  174.                 // Inform the user
  175.                 System.Windows.Forms.MessageBox.Show("Could not locate \"CompiledEffect.fxo\".\n\n" +
  176.                     "This file is created as part of the project build process,\n" +
  177.                     "so the associated project must be compiled inside Visual\n" +
  178.                     "Studio before attempting to run this sample.\n\n" +
  179.                     "If receiving this error even after compiling the project,\n" +
  180.                     "it's likely there was a problem compiling the effect file.\n" +
  181.                     "Check the build log to verify the custom build step was\n" +
  182.                     "run and to look for possible fxc compile errors.",  "File Not Found",
  183.                     System.Windows.Forms.MessageBoxButtons.OK,
  184.                     System.Windows.Forms.MessageBoxIcon.Error);
  185.  
  186.                 // Rethrow
  187.                 throw;
  188.             }
  189.  
  190.             // Setup the camera's view parameters
  191.             camera.SetViewParameters(new Vector3(0.0f, 0.0f, -5.0f), Vector3.Empty);
  192.         }
  193.         
  194.         /// <summary>
  195.         /// This event will be fired immediately after the Direct3D device has been 
  196.         /// reset, which will happen after a lost device scenario. This is the best location to 
  197.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  198.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  199.         /// event. 
  200.         /// </summary>
  201.         private void OnResetDevice(object sender, DeviceEventArgs e)
  202.         {
  203.             SurfaceDescription desc = e.BackBufferDescription;
  204.             // Create a sprite to help batch calls when drawing many lines of text
  205.             textSprite = new Sprite(e.Device);
  206.  
  207.             // Set effect variables as needed
  208.             effect.SetValue("g_MaterialAmbientColor", new ColorValue(0.35f, 0.35f, 0.35f, 0));
  209.             effect.SetValue("g_MaterialDiffuseColor", WhiteColor);
  210.  
  211.             // To read or write to D3DX effect variables we can use the string name 
  212.             // instead of using handles, however it improves perf to use handles since then 
  213.             // D3DX won't have to spend time doing string compares
  214.             techniqueHandle = effect.GetTechnique("RenderScene");
  215.             timeHandle = effect.GetParameter(null, "g_fTime");
  216.             worldHandle = effect.GetParameter(null, "g_mWorld");
  217.             worldViewHandle = effect.GetParameter(null, "g_mWorldViewProjection");
  218.             meshTextureHandle = effect.GetParameter(null, "g_MeshTexture");
  219.  
  220.             // Setup the camera's projection parameters
  221.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  222.             camera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, 0.1f, 1000.0f);
  223.             camera.SetWindow(desc.Width, desc.Height);
  224.  
  225.             // Setup UI locations
  226.             hud.SetLocation(desc.Width-170, 0);
  227.             hud.SetSize(170,170);
  228.         }
  229.  
  230.         /// <summary>
  231.         /// This event function will be called fired after the Direct3D device has 
  232.         /// entered a lost state and before Device.Reset() is called. Resources created
  233.         /// in the OnResetDevice callback should be released here, which generally includes all 
  234.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  235.         /// information about lost devices.
  236.         /// </summary>
  237.         private void OnLostDevice(object sender, EventArgs e)
  238.         {
  239.             if (textSprite != null)
  240.             {
  241.                 textSprite.Dispose();
  242.                 textSprite = null;
  243.             }
  244.         }
  245.  
  246.         /// <summary>
  247.         /// This callback function will be called immediately after the Direct3D device has 
  248.         /// been destroyed, which generally happens as a result of application termination or 
  249.         /// windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  250.         /// should be released here, which generally includes all Pool.Managed resources. 
  251.         /// </summary>
  252.         private void OnDestroyDevice(object sender, EventArgs e)
  253.         {
  254.         }
  255.  
  256.         /// <summary>
  257.         /// This callback function will be called once at the beginning of every frame. This is the
  258.         /// best location for your application to handle updates to the scene, but is not 
  259.         /// intended to contain actual rendering calls, which should instead be placed in the 
  260.         /// OnFrameRender callback.  
  261.         /// </summary>
  262.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  263.         {
  264.             // Update the camera's position based on user input 
  265.             camera.FrameMove(elapsedTime);
  266.  
  267.             // Get the world matrix
  268.             Matrix worldMatrix = worldCenter * camera.WorldMatrix;
  269.  
  270.             // Update the effect's variables
  271.             effect.SetValue(worldViewHandle, worldMatrix * camera.ViewMatrix * camera.ProjectionMatrix);
  272.             effect.SetValue(worldHandle, worldMatrix);
  273.             effect.SetValue(timeHandle, (float)appTime);
  274.         }
  275.  
  276.         /// <summary>
  277.         /// This callback function will be called at the end of every frame to perform all the 
  278.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  279.         /// repainted. After this function has returned, the sample framework will call 
  280.         /// Device.Present to display the contents of the next buffer in the swap chain
  281.         /// </summary>
  282.         public void OnFrameRender(Device device, double appTime, float elapsedTime)
  283.         {
  284.             bool beginSceneCalled = false;
  285.  
  286.             // Clear the render target and the zbuffer 
  287.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x002D32AA, 1.0f, 0);
  288.             try
  289.             {
  290.                 device.BeginScene();
  291.                 beginSceneCalled = true;
  292.  
  293.                 int passes = effect.Begin(0);
  294.                 for(int iPass = 0; iPass < passes; iPass++)
  295.                 {
  296.                     effect.BeginPass(iPass);
  297.                     mesh.Render(device);
  298.                     effect.EndPass();
  299.                 }
  300.  
  301.                 effect.End();
  302.                 // Show frame rate
  303.                 RenderText();
  304.  
  305.                 // Show UI
  306.                 hud.OnRender(elapsedTime);
  307.             }
  308.             finally
  309.             {
  310.                 if (beginSceneCalled)
  311.                     device.EndScene();
  312.             }
  313.         }
  314.  
  315.         /// <summary>
  316.         /// Render the help and statistics text. This function uses the Font object for 
  317.         /// efficient text rendering.
  318.         /// </summary>
  319.         private void RenderText()
  320.         {
  321.             TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
  322.  
  323.             // Output statistics
  324.             txtHelper.Begin();
  325.             txtHelper.SetInsertionPoint(5,5);
  326.             txtHelper.SetForegroundColor(System.Drawing.Color.Yellow);
  327.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  328.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  329.  
  330.             // Draw help
  331.             if (isHelpShowing)
  332.             {
  333.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  334.                 txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  335.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  336.  
  337.                 txtHelper.SetInsertionPoint(40, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  338.                 txtHelper.DrawTextLine("Rotate model: Left mouse button");
  339.                 txtHelper.DrawTextLine("Rotate camera: Right mouse button");
  340.                 txtHelper.DrawTextLine("Zoom camera: Mouse wheel scroll");
  341.                 txtHelper.DrawTextLine("Quit: Esc");
  342.                 txtHelper.DrawTextLine("Hide help: F1");
  343.             }
  344.             else
  345.             {
  346.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*2);
  347.                 txtHelper.SetForegroundColor(System.Drawing.Color.White);
  348.                 txtHelper.DrawTextLine("Press F1 for help");
  349.             }
  350.  
  351.             txtHelper.End();
  352.         }
  353.  
  354.         /// <summary>
  355.         /// As a convenience, the sample framework inspects the incoming windows messages for
  356.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  357.         /// messages to the application.  The framework does not remove the underlying keystroke 
  358.         /// messages, which are still passed to the application's MsgProc callback.
  359.         /// </summary>
  360.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  361.         {
  362.             if (isKeyDown)
  363.             {
  364.                 switch(key)
  365.                 {
  366.                     case System.Windows.Forms.Keys.F1:
  367.                         isHelpShowing = !isHelpShowing;
  368.                         break;
  369.                 }
  370.             }
  371.         }
  372.  
  373.         /// <summary>
  374.         /// Before handling window messages, the sample framework passes incoming windows 
  375.         /// messages to the application through this callback function. If the application sets 
  376.         /// noFurtherProcessing to true, the sample framework will not process the message
  377.         /// </summary>
  378.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  379.         {
  380.             // Give the dialog a chance to handle the message first
  381.             noFurtherProcessing = hud.MessageProc(hWnd, msg, wParam, lParam);
  382.             if (noFurtherProcessing)
  383.                 return IntPtr.Zero;
  384.  
  385.             // Pass all remaining windows messages to camera so it can respond to user input
  386.             camera.HandleMessages(hWnd, msg, wParam, lParam);
  387.  
  388.             return IntPtr.Zero;
  389.         }
  390.  
  391.         /// <summary>
  392.         /// Initializes the application
  393.         /// </summary>
  394.         public void InitializeApplication()
  395.         {
  396.             int y = 10;
  397.             // Initialize the HUD
  398.             Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
  399.             Button toggleRef = hud.AddButton(ToggleReference,"Toggle reference (F3)", 35, y += 24, 125,22);
  400.             Button changeDevice = hud.AddButton(ChangeDevice,"Change Device (F2)", 35, y += 24, 125,22);
  401.             // Hook the button events for when these items are clicked
  402.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  403.             toggleRef.Click += new EventHandler(OnRefClicked);
  404.             changeDevice.Click += new EventHandler(OnChangeDevicClicked);
  405.         }
  406.  
  407.         /// <summary>Called when the change device button is clicked</summary>
  408.         private void OnChangeDevicClicked(object sender, EventArgs e)
  409.         {
  410.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  411.         }
  412.  
  413.         /// <summary>Called when the full screen button is clicked</summary>
  414.         private void OnFullscreenClicked(object sender, EventArgs e)
  415.         {
  416.             sampleFramework.ToggleFullscreen();
  417.         }
  418.  
  419.         /// <summary>Called when the ref button is clicked</summary>
  420.         private void OnRefClicked(object sender, EventArgs e)
  421.         {
  422.             sampleFramework.ToggleReference();
  423.         }
  424.  
  425.         /// <summary>
  426.         /// Entry point to the program. Initializes everything and goes into a message processing 
  427.         /// loop. Idle time is used to render the scene.
  428.         /// </summary>
  429.         static int Main() 
  430.         {
  431.             using(Framework sampleFramework = new Framework())
  432.             {
  433.                 CompiledEffect sample = new CompiledEffect(sampleFramework);
  434.                 // Set the callback functions. These functions allow the sample framework to notify
  435.                 // the application about device changes, user input, and windows messages.  The 
  436.                 // callbacks are optional so you need only set callbacks for events you're interested 
  437.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  438.                 // framework won't be able to reset your device since the application must first 
  439.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  440.                 // device created/destroyed callbacks then the sample framework won't be able to 
  441.                 // recreate your device resources.
  442.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  443.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  444.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  445.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  446.  
  447.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  448.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  449.  
  450.                 sampleFramework.SetCallbackInterface(sample);
  451.                 try
  452.                 {
  453.  
  454.                     // Show the cursor and clip it when in full screen
  455.                     sampleFramework.SetCursorSettings(true, true);
  456.  
  457.                     // Initialize
  458.                     sample.InitializeApplication();
  459.  
  460.                     // Initialize the sample framework and create the desired window and Direct3D 
  461.                     // device for the application. Calling each of these functions is optional, but they
  462.                     // allow you to set several options which control the behavior of the sampleFramework.
  463.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  464.                     sampleFramework.CreateWindow("Compiled Effect");
  465.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  466.                         sample);
  467.  
  468.                     // Pass control to the sample framework for handling the message pump and 
  469.                     // dispatching render calls. The sample framework will call your FrameMove 
  470.                     // and FrameRender callback when there is idle time between handling window messages.
  471.                     sampleFramework.MainLoop();
  472.  
  473.                 }
  474. #if(DEBUG)
  475.                 catch (Exception e)
  476.                 {
  477.                     // In debug mode show this error (maybe - depending on settings)
  478.                     sampleFramework.DisplayErrorMessage(e);
  479. #else
  480.             catch
  481.             {
  482.                 // In release mode fail silently
  483. #endif
  484.                     // Ignore any exceptions here, they would have been handled by other areas
  485.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  486.                 }
  487.  
  488.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  489.                 // appropriate callback functions and therefore don't require any cleanup code here.
  490.                 return sampleFramework.ExitCode;
  491.             }
  492.         }
  493.     }
  494. }
  495.